using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MimeMapping;
using Aspose.Cells;
using Aspose.Words;
using Aspose.Slides;
using SkiaSharp;
using System.Runtime.InteropServices;


namespace ManageSystem.Controllers
{
    /// <summary>
    /// ADD and manage project resource
    /// </summary>
    [Route("ManageSystem/[controller]/[action]")]
    [ApiController]
    [Produces("application/json")]
    [Authorize(Policy = "Permission")]
    public class ProjectResourceController : ControllerBase
    {
        // 注入IWebHostEnvironment
        private readonly IWebHostEnvironment _webHostEnvironment;
        // 项目文件根目录
        private readonly string rootFilePath;
        public ProjectResourceController(IWebHostEnvironment webHostEnvironment)
        {
            _webHostEnvironment = webHostEnvironment;
            rootFilePath = Path.Combine(_webHostEnvironment.ContentRootPath, "uploads");
            if (!Directory.Exists(rootFilePath))
            {
                Directory.CreateDirectory(rootFilePath);
            }
        }

        /// <summary>
        /// 合并分片的文件
        /// </summary>
        /// <param name="filePath">合并后文件保存目录</param>
        /// <param name="tmpPath">临时文件夹目录</param>
        public static async Task MergeFileAsync(string filePath, string tmpPath)
        {
            Console.WriteLine("-------------------------WINDOWS---------------------------");
            //获得下面的所有文件
            var files = Directory.GetFiles(tmpPath);
            string fileStr = "";
            foreach (string file in files)
            {
                fileStr += file.ToString() + " ";
            }
            Console.WriteLine(fileStr);
            Console.WriteLine(Directory.Exists(filePath));

            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                try
                {
                    //排一下序，保证从0-N Write
                    var fileParts = files.OrderBy(x => x.Length).ThenBy(x => x);
                    foreach (var part in fileParts)
                    {
                        var bytes = await System.IO.File.ReadAllBytesAsync(part);
                        await fs.WriteAsync(bytes, 0, bytes.Length);
                        bytes = null;
                        //删除分块
                        System.IO.File.Delete(part);
                    }
                    await fs.FlushAsync();
                    fs.Close();
                    //删除临时文件夹和分片文件
                    Directory.Delete(tmpPath);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    System.IO.File.Delete(tmpPath);
                }
            }
        }

        /// <summary>
        /// 合并分片的文件（linux）
        /// </summary>
        /// <param name="filePath">合并后文件保存目录</param>
        /// <param name="tmpPath">临时文件夹目录</param>
        public static void MergeFileInLinuxAsync(string filePath, string tmpPath)
        {
            Console.WriteLine("-------------------------linux---------------------------");
            try
            {
                //获得下面的所有文件并排序
                var files = Directory.GetFiles(tmpPath).OrderBy(x => x.Length).ThenBy(x => x);
                string fileStr = "";
                foreach (string file in files)
                {
                    fileStr += file.ToString() + " ";
                }
                Console.WriteLine(fileStr);

                string command = "cat " + fileStr + "> " + filePath;
                string result = "";
                Console.WriteLine(command);
                using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
                {
                    proc.StartInfo.FileName = "/bin/bash";
                    proc.StartInfo.Arguments = "-c \" " + command + " \"";
                    proc.StartInfo.UseShellExecute = false;
                    proc.StartInfo.RedirectStandardOutput = true;
                    proc.StartInfo.RedirectStandardError = true;
                    proc.Start();

                    result += proc.StandardOutput.ReadToEnd();
                    result += proc.StandardError.ReadToEnd();

                    proc.WaitForExit();
                }
                Console.WriteLine(result);
                Console.WriteLine(Directory.Exists(filePath));
                foreach (string file in files)
                {
                    System.IO.File.Delete(file);
                }
                //删除临时文件夹和分片文件
                Directory.Delete(tmpPath);
            }
            catch (Exception ex)
            {
                Console.WriteLine("合并报错：" + ex.Message);
            }

        }

        /// <summary>
        ///分片上传项目资源
        ///</summary>
        ///<param name="projectGuid"></param>
        ///<param name="fileType"></param>
        ///<returns></returns>
        [HttpPost]
        [Authorize(Policy = "Permission")]
        public async Task<IActionResult> updateProjectResources(string projectGuid, string fileType)
        {
            if (fileType == null || fileType == "")
            {
                return BadRequest("文件类型为空！");
            }

            if (projectGuid == null || projectGuid == "")
            {
                return BadRequest("项目id为空！");
            }

            bool isCompleted = false;

            // F:\\ManageSystem\\ManageSystem-dotnetcore\\ManageSystem\\uploads\\${projectGuid}
            string projectFilePath = Path.Combine(rootFilePath, projectGuid);
            // if not exist
            if (!Directory.Exists(projectFilePath))
            {
                Directory.CreateDirectory(projectFilePath);
            }
            // F:\\ManageSystem\\ManageSystem-dotnetcore\\ManageSystem\\uploads\\${projectGuid}\\${resource}
            string fileTypePath = Path.Combine(projectFilePath, fileType);
            // if not exist
            if (!Directory.Exists(fileTypePath))
            {
                Directory.CreateDirectory(fileTypePath);
            }

            string fileName = Request.Form["name"];
            string guid = Request.Form["Guid"];
            // now chunkl
            int chunk = int.Parse(Request.Form["chunk"].ToString());
            int maxChunk = int.Parse(Request.Form["maxChunk"].ToString());
            // file 
            var file = Request.Form.Files["file"];



            // tmp directory (to save chunk file)
            string tmpPath = Path.Combine(fileTypePath, guid);
            if (!Directory.Exists(tmpPath))
            {
                Directory.CreateDirectory(tmpPath);
            }

            // chunk file dict
            string chunkFilePath = Path.Combine(tmpPath, fileName + chunk.ToString());

            using (var stream = new FileStream(chunkFilePath, FileMode.Create))
            {
                try
                {
                    await file.CopyToAsync(stream);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return BadRequest($"分片${chunk}写入失败:{e.Message}");
                }
            }

            if (chunk == maxChunk)
            {

                string filePath = Path.Combine(fileTypePath, fileName);
                // merge the file 
                try
                {
                    // 合并
                    if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        await MergeFileAsync(filePath, tmpPath);
                    }
                    else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        await MergeFileAsync(filePath, tmpPath);
                        //MergeFileInLinuxAsync(filePath, tmpPath);
                    }
                    isCompleted = true;
                    Console.WriteLine($"{Directory.Exists(filePath)}--------------------");
                }
                catch (Exception e)
                {
                    return BadRequest($"分片合并失败：{e.Message}");
                }
            }
            // 分片上传没？你猜
            return Ok(isCompleted);

        }


        ///<summary>
        ///获取项目资源中的某一类文件的所有文件名
        ///</summary>
        ///<param name="projectGuid"></param>
        ///<param name="fileType"></param>
        [HttpGet]
        public IActionResult queryFileNamesByType(string projectGuid, string fileType)
        {
            try
            {
                string projectFilePath = Path.Combine(rootFilePath, projectGuid);
                if (!Directory.Exists(projectFilePath))
                {
                    Directory.CreateDirectory(projectFilePath);
                }

                string fileTypePath = Path.Combine(projectFilePath, fileType);
                // if not exist
                if (!Directory.Exists(fileTypePath))
                {
                    Directory.CreateDirectory(fileTypePath);
                }

                List<string> fileNameList = new List<string>();

                // get filename
                foreach (var item in Directory.GetFiles(fileTypePath))
                {
                    fileNameList.Add(Path.GetFileName(item));
                }

                return Ok(fileNameList);
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }

        }

        ///<summary>
        ///显示项目资源中的某一个文件,或者把对应文件转换为pdf格式
        ///</summary>
        ///<param name="projectGuid"></param>
        ///<param name="fileType"></param>
        ///<param name="fileName"></param>
        ///<param name="toPDF"></param>
        [HttpGet]
        public IActionResult queryProjectResource(string projectGuid, string fileType, string fileName, bool toPDF = false)
        {
            // Console.WriteLine(toPDF);
            try
            {
                string projectFilePath = Path.Combine(rootFilePath, projectGuid);
                string fileTypePath = Path.Combine(projectFilePath, fileType);
                string filePath = Path.Combine(fileTypePath, fileName);
                // change the filepath if need to change the file type
                if (toPDF)
                {

                    string fileExtentionName = Path.GetExtension(fileName);
                    string pdfPath = Path.Combine(fileTypePath, Path.GetFileNameWithoutExtension(fileName) + ".pdf");

                    // word
                    if (fileExtentionName.Contains("doc"))
                    {
                        // generate a word file
                        Document document = new(filePath);
                        // save as pdf
                        document.Save(@pdfPath, Aspose.Words.SaveFormat.Pdf);
                    }
                    else if (fileExtentionName.Contains("xls"))
                    {
                        Workbook excel = new(filePath);
                        excel.Save(@pdfPath, Aspose.Cells.SaveFormat.Pdf);
                    }
                    else if (fileExtentionName.Contains("pptx"))
                    {
                        Presentation ppt = new(filePath);
                        // save as pdf
                        ppt.Save(@pdfPath, Aspose.Slides.Export.SaveFormat.Pdf);
                    }
                    else
                    {
                        return BadRequest("仅支持转换word、excel和ppt文件！");
                    }

                    // update filepath to be return
                    filePath = pdfPath;
                    Console.WriteLine(filePath);
                }
                // filestream
                // todo for big files
                var stream = System.IO.File.OpenRead(filePath);
                Console.WriteLine($"---------------path:{filePath}-----------------");
                return File(stream, MimeUtility.GetMimeMapping(filePath), Path.GetFileName(filePath));
                // blob
            }
            catch (FileNotFoundException)
            {
                return NotFound($"文件{fileName}不存在！");
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }
        }


        ///<summary>
        ///查询某个资源的上传时间
        ///</summary>
        ///<param name="projectGuid"></param>
        ///<param name="fileType"></param>
        ///<param name="fileName"></param>
        [HttpGet]
        public IActionResult queryProjectResourceUploadTime(string projectGuid, string fileType, string fileName)
        {
            string projectFilePath = Path.Combine(rootFilePath, projectGuid);
            string fileTypePath = Path.Combine(projectFilePath, fileType);
            string filePath = Path.Combine(fileTypePath, fileName);

            try
            {
                // filestream
                FileInfo fileInfo = new FileInfo(filePath);

                // blob
                return Ok(fileInfo.CreationTime.ToString("yyyy-MM-dd HH:mm:ss"));
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }
        }

        ///<summary>
        ///删除项目资源中的某一个文件
        ///</summary>
        ///<param name="projectGuid"></param>
        ///<param name="fileType"></param>
        ///<param name="fileName"></param>
        [HttpDelete]
        public IActionResult deleteProjectResource(string projectGuid, string fileType, string fileName)
        {
            string projectFilePath = Path.Combine(rootFilePath, projectGuid);
            string fileTypePath = Path.Combine(projectFilePath, fileType);
            string filePath = Path.Combine(fileTypePath, fileName);

            try
            {
                // filestream
                System.IO.File.Delete(filePath);

                return NoContent();
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }
        }

    }
}